Proyecto Computer Vision - Tercera Entrega¶

Caso de uso generalizable para Object Tracking and People Tracking¶

Autor

  • Adolfo Fuentes Jofré

1. Introducción¶

Problema o necesidad¶

Un problema recurrente en la optimización de Layout (posición de los productos) es generar áreas con mapas de calor que representan el flujo de clientes, esta información es útil para saber que zonas de la tienda son mas concurridas y tiene un mayor flujo de personas de manera tal de posicionar los productos de mayor valor para en negocio en esa zona y/o reoptimizar en Layout. Este problema es tranversal en mutiples Industrias desde Retail, Centros Comerciales hasta un Casino.

Dataset¶

Video de camara de seguridad de personas caminando en un centro comercial. Video de uso gratuito (Free Stock video footage YouTube)

Objetivos¶

Generar un sistema automatizado que permita:

  • Realizar el Tracking de las personas caminando
  • Delimitar en un cuadro a las personas y asignar un id distinto a cada persona
  • Contar el flujo total de personas que transitan por una zona especifica

2. Preprocesamiento¶

Librerias¶

In [1]:
import torchvision
import cv2
import matplotlib.pyplot as plt
from PIL import Image
from torchvision import datasets, models, transforms as T

Abrimos la Imagen

In [2]:
im = Image.open('Out\\frame0.jpg')
plt.imshow(im)
Out[2]:
<matplotlib.image.AxesImage at 0x1d22fce8850>
In [3]:
img = cv2.imread('Out\\frame0.jpg') # Read image with cv2
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # Convert to RGB

Definimos un par de coordenadas

In [4]:
coor=[(443.22217, 432.3046), (495.6839, 569.45807)]
coor
Out[4]:
[(443.22217, 432.3046), (495.6839, 569.45807)]
In [5]:
aux=tuple(tuple(map(int, tup)) for tup in coor) # transforma a entero
cv2.rectangle(img, aux[0],aux[1],color=(0, 255, 0), thickness=3) 
cv2.putText(img,'Person',aux[0],  cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0),thickness=3)
Out[5]:
array([[[128, 128, 128],
        [128, 128, 128],
        [128, 128, 128],
        ...,
        [148, 150, 147],
        [149, 151, 148],
        [149, 151, 148]],

       [[128, 128, 128],
        [128, 128, 128],
        [128, 128, 128],
        ...,
        [148, 150, 147],
        [149, 151, 148],
        [149, 151, 148]],

       [[128, 128, 128],
        [128, 128, 128],
        [128, 128, 128],
        ...,
        [148, 150, 147],
        [148, 150, 147],
        [149, 151, 148]],

       ...,

       [[200, 202, 199],
        [201, 203, 200],
        [199, 201, 198],
        ...,
        [229, 229, 229],
        [229, 229, 229],
        [229, 229, 229]],

       [[200, 202, 199],
        [200, 202, 199],
        [201, 203, 200],
        ...,
        [229, 229, 229],
        [229, 229, 229],
        [229, 229, 229]],

       [[200, 202, 199],
        [199, 201, 198],
        [202, 204, 201],
        ...,
        [229, 229, 229],
        [229, 229, 229],
        [229, 229, 229]]], dtype=uint8)

Graficamos la imagen con el recuadro y el label "Person"

In [6]:
plt.imshow(img)
Out[6]:
<matplotlib.image.AxesImage at 0x1d2302bd3c0>

3. Transfer Learning¶

Importaremos una restnet pre-entrenada y el label de los disntos objetos que detecta

In [7]:
model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)

model.eval()

COCO_INSTANCE_CATEGORY_NAMES = [

    '__background__', 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus',
    'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'N/A', 'stop sign',
    'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
    'elephant', 'bear', 'zebra', 'giraffe', 'N/A', 'backpack', 'umbrella', 'N/A', 'N/A',
    'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball',
    'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket',
    'bottle', 'N/A', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl',
    'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza',
    'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'N/A', 'dining table',
    'N/A', 'N/A', 'toilet', 'N/A', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
    'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'N/A', 'book',
    'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'
]
C:\Users\Usuario\.conda\envs\cv\lib\site-packages\torchvision\models\_utils.py:208: UserWarning: The parameter 'pretrained' is deprecated since 0.13 and may be removed in the future, please use 'weights' instead.
  warnings.warn(
C:\Users\Usuario\.conda\envs\cv\lib\site-packages\torchvision\models\_utils.py:223: UserWarning: Arguments other than a weight enum or `None` for 'weights' are deprecated since 0.13 and may be removed in the future. The current behavior is equivalent to passing `weights=FasterRCNN_ResNet50_FPN_Weights.COCO_V1`. You can also use `weights=FasterRCNN_ResNet50_FPN_Weights.DEFAULT` to get the most up-to-date weights.
  warnings.warn(msg)

Funciones¶

In [8]:
def get_prediction(img_path, threshold):
    """
    Realiza una predicción de detección de objetos en una imagen utilizando un modelo pre-entrenado.

    Parámetros:
    - img_path (str): Ruta de la imagen de entrada.
    - threshold (float): Umbral de confianza para filtrar las predicciones.

    Retorna:
    - pred_boxes1 (list): Lista de cajas delimitadoras (bounding boxes) de los objetos detectados en la imagen.
    - pred_class1 (list): Lista de clases de los objetos detectados en la imagen.

    """

    img = Image.open(img_path)  # Cargar la imagen
    transform = T.Compose([T.ToTensor()])  # Definir la transformación de PyTorch
    img = transform(img)  # Aplicar la transformación a la imagen

    pred = model([img])  # Pasar la imagen al modelo para obtener las predicciones

    # Obtener la clase de la predicción y su puntuación
    pred_class = [COCO_INSTANCE_CATEGORY_NAMES[i] for i in list(pred[0]['labels'].numpy())]
    pred_boxes = [[(i[0], i[1]), (i[2], i[3])] for i in list(pred[0]['boxes'].detach().numpy())]
    pred_score = list(pred[0]['scores'].detach().numpy())

    # Filtrar las predicciones basadas en el umbral de confianza
    pred_t = [pred_score.index(x) for x in pred_score if x > threshold][-1]
    pred_boxes = pred_boxes[:pred_t+1]
    pred_class = pred_class[:pred_t+1]

    # Filtrar solo las predicciones de la clase 'person'
    myIndices = [i for i in range(len(pred_class)) if pred_class[i] == 'person']
    pred_class1 = [pred_class[i] for i in myIndices]
    pred_boxes1 = [pred_boxes[i] for i in myIndices]

    return pred_boxes1, pred_class1

def object_detection_api(img_path, threshold=0.5, rect_th=3, text_size=3, text_th=3):
    """
    Realiza la detección de objetos en una imagen y muestra el resultado visualmente.

    Parámetros:
    - img_path (str): Ruta de la imagen de entrada.
    - threshold (float, opcional): Umbral de confianza para filtrar las predicciones (por defecto es 0.5).
    - rect_th (int, opcional): Grosor del contorno de las cajas delimitadoras (por defecto es 3).
    - text_size (int, opcional): Tamaño del texto de las etiquetas (por defecto es 3).
    - text_th (int, opcional): Grosor del texto de las etiquetas (por defecto es 3).
    
    Retorna:
    - len(boxes): la cantidad de objetos (personas) detectados en la imagen.

    """

    boxes, pred_cls = get_prediction(img_path, threshold)  # Obtener las predicciones de detección de objetos

    img = cv2.imread(img_path)  # Leer la imagen utilizando OpenCV
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # Convertir la imagen de BGR a RGB

    # Dibujar las cajas delimitadoras y etiquetas en la imagen
    for i in range(len(boxes)):
        aux = tuple(tuple(map(int, tup)) for tup in boxes[i])
        cv2.rectangle(img, aux[0], aux[1], color=(0, 255, 0), thickness=rect_th)  # Dibujar el contorno de la caja delimitadora
        cv2.putText(img, str(i), aux[0], cv2.FONT_HERSHEY_SIMPLEX, text_size, (0, 255, 0), thickness=text_th)  # Mostrar la etiqueta del objeto

    plt.figure(figsize=(20, 30))  
    plt.imshow(img)  
    plt.xticks([]) 
    plt.yticks([])  
    plt.show()  # Mostrar la figura
    
    return len(boxes)


def object_detection_api_without_plot(img_path, threshold=0.5, rect_th=3, text_size=3, text_th=3):
    """
    Realiza la detección de objetos en una imagen y muestra el resultado visualmente.

    Parámetros:
    - img_path (str): Ruta de la imagen de entrada.
    - threshold (float, opcional): Umbral de confianza para filtrar las predicciones (por defecto es 0.5).    
    Retorna:
    - len(boxes): la cantidad de objetos (personas) detectados en la imagen.

    """

    boxes, pred_cls = get_prediction(img_path, threshold)  # Obtener las predicciones de detección de objetos
    
    return len(boxes)

4. Predicción¶

In [9]:
boxes, pred_cls = get_prediction('Out\\frame0.jpg', 0.8)
In [10]:
boxes
Out[10]:
[[(443.22217, 432.3046), (495.6839, 569.45807)],
 [(501.18707, 300.63504), (548.6047, 415.24503)],
 [(966.0561, 213.89882), (1010.95636, 321.63043)],
 [(775.5949, 99.51255), (807.30255, 185.5091)],
 [(173.25558, 290.7064), (221.5165, 404.7594)],
 [(1195.2103, 97.64532), (1234.1835, 183.02487)],
 [(974.37933, 314.29733), (1028.7239, 427.42883)],
 [(803.32416, 87.04374), (835.83984, 177.20128)],
 [(760.0624, 635.7334), (827.81213, 719.68994)],
 [(615.11206, 115.60903), (658.35144, 204.57394)],
 [(945.49585, 470.17923), (1012.7888, 586.4515)],
 [(759.35046, 338.6047), (807.22565, 437.8828)],
 [(133.52132, 29.448956), (174.58212, 107.219475)],
 [(471.4505, 159.81447), (511.04123, 257.3289)],
 [(228.30536, 330.32376), (267.24747, 428.82764)],
 [(59.997746, 87.70881), (95.77105, 168.62614)],
 [(1074.6514, 10.540487), (1103.3835, 83.69601)],
 [(378.01562, 178.02309), (418.84055, 270.67245)],
 [(260.2885, 342.58185), (302.42795, 447.8906)],
 [(1053.0913, 12.96877), (1081.9692, 81.528984)],
 [(924.1393, 0.8561452), (960.6697, 122.83047)],
 [(100.124954, 1.5615566), (132.55731, 35.11881)],
 [(657.0554, 67.776184), (691.8573, 155.52673)],
 [(871.3717, 6.7900934), (896.13574, 73.67567)],
 [(727.94006, 30.92497), (755.0558, 97.640015)],
 [(531.54846, 51.92416), (564.2414, 136.32295)],
 [(485.63174, 4.369262), (513.7344, 73.45789)],
 [(21.844887, 530.03906), (92.2304, 656.13727)],
 [(1113.8655, 7.714753), (1150.1993, 90.23451)],
 [(231.45007, 4.2224317), (269.77887, 94.30402)],
 [(568.6086, 46.845814), (595.85565, 133.0215)],
 [(596.371, 65.716286), (621.37915, 143.22125)],
 [(1214.0133, 0.0), (1235.3495, 34.20509)],
 [(281.86777, 338.0434), (329.47772, 430.5924)],
 [(304.13635, 342.21066), (338.56122, 423.18076)],
 [(1145.718, 54.933544), (1187.6442, 133.9454)],
 [(1264.701, 66.73807), (1280.0, 126.33597)]]
In [11]:
pred_cls
Out[11]:
['person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person',
 'person']
In [12]:
a=object_detection_api('Out\\frame0.jpg', threshold=0.8, text_size=1) 
In [13]:
a
Out[13]:
37

Detectó 37 personas en esta imagen con el umbral de 80%

5. Analisis de Sensibilidad Previo¶

Modificarémos los umbrales (threshold) de detección para ver como varía la detección de personas de la RestNet utilizando distintos umbrales.

In [14]:
b=object_detection_api('Out\\frame0.jpg', threshold=0.99, text_size=1) 
In [15]:
b=object_detection_api('Out\\frame0.jpg', threshold=0.5, text_size=1) 
In [16]:
b
Out[16]:
44

Detectó 44 personas en esta imagen con el umbral de 50%

Heat Map¶

Usaremos una imagen de referencia para crear un heat map con el centroide de la detección

In [17]:
boxes, pred_cls = get_prediction('Out\\frame0.jpg', 0.5)
In [18]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

df = pd.DataFrame(boxes, columns=['par1', 'par2'])
# Splitting the 'lat_long' column into two separate columns
df[['x1', 'y1']] = df['par1'].apply(pd.Series)
df[['x2', 'y2']] = df['par2'].apply(pd.Series)
df['x1']=df['x1'].astype(int)
df['y1']=df['y1'].astype(int)
df['x2']=df['x2'].astype(int)
df['y2']=df['y2'].astype(int)
df['xmean']=(df['x1']+df['x2'])/2
df['ymean']=(df['y1']+df['y2'])/2
In [19]:
x =df['xmean']
y =df['ymean']

plt.hist2d(x,y, bins=[np.arange(0,1280,10),np.arange(0,720,10)])
plt.gca().invert_yaxis()

Comparamos el Heat Map con la foto real para confirmar que el grafico este correcto

In [20]:
im = Image.open('Out\\frame0.jpg')
plt.imshow(im)
Out[20]:
<matplotlib.image.AxesImage at 0x1d23c7e7880>

6. Deployment¶

Deployment para toda la BBDD de Imagenes¶

In [21]:
from datetime import datetime
import pandas as pd
import seaborn as sns
In [22]:
a=[]
q=[]
for i in range (0,136):
    start_time = datetime.now() # grabar el tiempo al inicio de cada iteración

    q1=object_detection_api_without_plot("Out\\frame%i.jpg" % i, threshold=0.8, text_size=1) 

    end_time = datetime.now() # grabar el tiempo al finalizar cada predicción
    total=end_time - start_time
    print('Duration: {}'.format(total))
    a.append(total.total_seconds())
    q.append(q1) # agregar a una lista la cantidad de segundos de cada iteración
Duration: 0:00:03.477468
Duration: 0:00:03.455627
Duration: 0:00:03.349561
Duration: 0:00:03.038808
Duration: 0:00:03.029607
Duration: 0:00:03.597913
Duration: 0:00:03.462557
Duration: 0:00:03.569637
Duration: 0:00:03.328516
Duration: 0:00:03.703719
Duration: 0:00:04.081351
Duration: 0:00:03.168633
Duration: 0:00:03.143573
Duration: 0:00:03.130546
Duration: 0:00:03.201127
Duration: 0:00:02.976145
Duration: 0:00:03.985306
Duration: 0:00:03.505713
Duration: 0:00:03.031217
Duration: 0:00:03.061782
Duration: 0:00:03.400111
Duration: 0:00:03.112522
Duration: 0:00:03.105371
Duration: 0:00:03.238456
Duration: 0:00:02.933087
Duration: 0:00:04.027796
Duration: 0:00:03.534075
Duration: 0:00:03.137903
Duration: 0:00:03.028016
Duration: 0:00:03.097845
Duration: 0:00:02.928870
Duration: 0:00:03.072282
Duration: 0:00:03.086602
Duration: 0:00:03.131398
Duration: 0:00:03.145754
Duration: 0:00:03.368542
Duration: 0:00:03.757996
Duration: 0:00:03.463804
Duration: 0:00:03.127896
Duration: 0:00:03.179658
Duration: 0:00:03.044450
Duration: 0:00:03.176788
Duration: 0:00:03.025282
Duration: 0:00:03.097436
Duration: 0:00:03.032008
Duration: 0:00:03.079955
Duration: 0:00:03.039836
Duration: 0:00:03.130766
Duration: 0:00:03.182610
Duration: 0:00:03.311971
Duration: 0:00:03.254760
Duration: 0:00:03.148362
Duration: 0:00:03.345377
Duration: 0:00:03.282234
Duration: 0:00:03.032623
Duration: 0:00:03.072148
Duration: 0:00:03.268346
Duration: 0:00:03.385920
Duration: 0:00:02.945458
Duration: 0:00:02.968667
Duration: 0:00:03.293309
Duration: 0:00:03.377194
Duration: 0:00:03.007043
Duration: 0:00:03.766000
Duration: 0:00:03.731162
Duration: 0:00:03.129318
Duration: 0:00:02.883450
Duration: 0:00:02.979545
Duration: 0:00:02.953491
Duration: 0:00:02.995939
Duration: 0:00:03.019846
Duration: 0:00:03.042848
Duration: 0:00:02.880998
Duration: 0:00:03.222097
Duration: 0:00:02.937458
Duration: 0:00:02.954649
Duration: 0:00:03.004023
Duration: 0:00:02.908451
Duration: 0:00:02.996545
Duration: 0:00:02.975183
Duration: 0:00:02.842713
Duration: 0:00:03.088294
Duration: 0:00:02.894740
Duration: 0:00:02.884184
Duration: 0:00:02.955321
Duration: 0:00:02.872028
Duration: 0:00:02.882997
Duration: 0:00:02.904756
Duration: 0:00:02.914393
Duration: 0:00:02.876630
Duration: 0:00:02.854172
Duration: 0:00:02.983024
Duration: 0:00:02.866874
Duration: 0:00:02.877342
Duration: 0:00:02.886569
Duration: 0:00:02.917564
Duration: 0:00:03.038374
Duration: 0:00:02.876570
Duration: 0:00:02.926714
Duration: 0:00:02.902250
Duration: 0:00:02.949982
Duration: 0:00:03.185080
Duration: 0:00:03.214656
Duration: 0:00:03.094802
Duration: 0:00:03.000047
Duration: 0:00:02.994071
Duration: 0:00:03.152516
Duration: 0:00:03.092038
Duration: 0:00:03.739364
Duration: 0:00:03.065818
Duration: 0:00:03.147165
Duration: 0:00:03.630099
Duration: 0:00:03.426025
Duration: 0:00:03.669775
Duration: 0:00:03.681535
Duration: 0:00:03.437565
Duration: 0:00:03.314245
Duration: 0:00:03.189518
Duration: 0:00:03.408209
Duration: 0:00:03.681147
Duration: 0:00:03.460315
Duration: 0:00:04.816128
Duration: 0:00:05.432338
Duration: 0:00:04.782818
Duration: 0:00:04.561741
Duration: 0:00:03.438461
Duration: 0:00:03.444109
Duration: 0:00:03.360569
Duration: 0:00:03.669406
Duration: 0:00:03.557897
Duration: 0:00:03.150764
Duration: 0:00:03.072196
Duration: 0:00:03.163625
Duration: 0:00:03.219815
Duration: 0:00:03.212050
Duration: 0:00:02.975588

Deployment para toda la BBDD de Imagenes con umbral del 0.5¶

In [23]:
a2=[]
q2=[]
box=[]
for i in range (0,136):
    start_time = datetime.now() # grabar el tiempo al inicio de cada iteración
    boxes, pred_cls = get_prediction("Out\\frame%i.jpg" % i, 0.5)
    q1=object_detection_api_without_plot("Out\\frame%i.jpg" % i, threshold=0.5, text_size=1) 
    end_time = datetime.now() # grabar el tiempo al finalizar cada predicción
    total=end_time - start_time
    print('Duration: {}'.format(total))
    a2.append(total.total_seconds())
    q2.append(q1) # agregar a una lista la cantidad de segundos de cada iteración
    box.append(boxes) 
Duration: 0:00:06.596606
Duration: 0:00:06.810957
Duration: 0:00:06.659540
Duration: 0:00:06.825866
Duration: 0:00:07.800866
Duration: 0:00:08.372996
Duration: 0:00:06.666737
Duration: 0:00:06.450156
Duration: 0:00:06.796775
Duration: 0:00:06.724257
Duration: 0:00:06.598453
Duration: 0:00:06.727366
Duration: 0:00:06.767956
Duration: 0:00:06.226181
Duration: 0:00:06.049187
Duration: 0:00:05.944107
Duration: 0:00:05.984675
Duration: 0:00:05.852392
Duration: 0:00:05.860287
Duration: 0:00:06.022663
Duration: 0:00:06.376641
Duration: 0:00:05.835493
Duration: 0:00:06.089443
Duration: 0:00:06.339559
Duration: 0:00:06.482644
Duration: 0:00:06.249502
Duration: 0:00:06.521721
Duration: 0:00:06.969412
Duration: 0:00:06.570502
Duration: 0:00:06.431079
Duration: 0:00:06.228738
Duration: 0:00:06.161716
Duration: 0:00:06.169368
Duration: 0:00:06.022433
Duration: 0:00:05.995674
Duration: 0:00:06.710109
Duration: 0:00:05.990407
Duration: 0:00:06.367969
Duration: 0:00:06.047187
Duration: 0:00:06.026206
Duration: 0:00:06.203654
Duration: 0:00:05.999995
Duration: 0:00:06.805040
Duration: 0:00:07.187817
Duration: 0:00:07.016086
Duration: 0:00:06.355007
Duration: 0:00:06.985449
Duration: 0:00:06.588185
Duration: 0:00:06.593221
Duration: 0:00:06.525539
Duration: 0:00:06.175297
Duration: 0:00:06.262076
Duration: 0:00:06.324680
Duration: 0:00:06.375045
Duration: 0:00:06.716227
Duration: 0:00:06.158418
Duration: 0:00:06.094979
Duration: 0:00:07.066368
Duration: 0:00:06.485178
Duration: 0:00:06.299164
Duration: 0:00:06.231758
Duration: 0:00:06.542005
Duration: 0:00:06.407392
Duration: 0:00:06.600131
Duration: 0:00:06.404667
Duration: 0:00:06.397865
Duration: 0:00:06.342808
Duration: 0:00:06.926023
Duration: 0:00:06.924490
Duration: 0:00:06.459600
Duration: 0:00:06.279892
Duration: 0:00:06.298043
Duration: 0:00:06.686645
Duration: 0:00:06.216372
Duration: 0:00:05.954757
Duration: 0:00:06.102213
Duration: 0:00:05.915516
Duration: 0:00:06.045349
Duration: 0:00:06.141603
Duration: 0:00:06.101974
Duration: 0:00:05.908459
Duration: 0:00:05.746497
Duration: 0:00:05.971676
Duration: 0:00:06.581387
Duration: 0:00:06.472023
Duration: 0:00:06.359681
Duration: 0:00:06.615011
Duration: 0:00:06.108421
Duration: 0:00:05.963362
Duration: 0:00:06.214528
Duration: 0:00:06.679923
Duration: 0:00:07.072498
Duration: 0:00:06.780616
Duration: 0:00:06.700573
Duration: 0:00:06.346705
Duration: 0:00:06.147339
Duration: 0:00:06.086752
Duration: 0:00:06.324896
Duration: 0:00:06.612091
Duration: 0:00:06.205655
Duration: 0:00:05.845059
Duration: 0:00:05.879961
Duration: 0:00:05.836137
Duration: 0:00:05.893570
Duration: 0:00:05.734879
Duration: 0:00:05.777898
Duration: 0:00:06.347659
Duration: 0:00:06.671724
Duration: 0:00:06.353454
Duration: 0:00:05.773754
Duration: 0:00:05.786047
Duration: 0:00:06.439009
Duration: 0:00:06.873638
Duration: 0:00:06.619458
Duration: 0:00:06.960732
Duration: 0:00:06.723467
Duration: 0:00:06.648762
Duration: 0:00:06.612932
Duration: 0:00:06.502028
Duration: 0:00:06.205317
Duration: 0:00:06.241760
Duration: 0:00:06.427285
Duration: 0:00:06.167727
Duration: 0:00:06.868486
Duration: 0:00:06.267513
Duration: 0:00:06.022302
Duration: 0:00:06.011519
Duration: 0:00:06.180361
Duration: 0:00:06.471297
Duration: 0:00:06.309113
Duration: 0:00:06.325057
Duration: 0:00:06.549484
Duration: 0:00:06.175435
Duration: 0:00:06.226722
Duration: 0:00:07.129457
Duration: 0:00:06.945828
In [24]:
df_concat=pd.DataFrame()
for i in range(0,136):
    df1 = pd.DataFrame(box[i], columns=['par1', 'par2'])
    # Splitting the 'lat_long' column into two separate columns
    df1[['x1', 'y1']] = df1['par1'].apply(pd.Series)
    df1[['x2', 'y2']] = df1['par2'].apply(pd.Series)
    df1['x1']=df1['x1'].astype(int)
    df1['y1']=df1['y1'].astype(int)
    df1['x2']=df1['x2'].astype(int)
    df1['y2']=df1['y2'].astype(int)
    df1['xmean']=(df1['x1']+df1['x2'])/2
    df1['ymean']=(df1['y1']+df1['y2'])/2
    df_concat=pd.concat([df_concat,df1])

7. Resultados¶

In [25]:
df = pd.DataFrame({'Duración':a})
df.describe()
Out[25]:
Duración
count 136.000000
mean 3.240421
std 0.397914
min 2.842713
25% 2.995472
50% 3.130656
75% 3.379376
max 5.432338
In [26]:
sns.histplot(data=df, x="Duración")
Out[26]:
<Axes: xlabel='Duración', ylabel='Count'>
In [27]:
df1 = pd.DataFrame({'Cantidad':q})
df1.describe()
Out[27]:
Cantidad
count 136.000000
mean 33.617647
std 3.806542
min 26.000000
25% 31.000000
50% 33.000000
75% 37.000000
max 42.000000
In [28]:
sns.histplot(data=df1, x="Cantidad")
Out[28]:
<Axes: xlabel='Cantidad', ylabel='Count'>
In [29]:
df_concat
Out[29]:
par1 par2 x1 y1 x2 y2 xmean ymean
0 (443.22217, 432.3046) (495.6839, 569.45807) 443 432 495 569 469.0 500.5
1 (501.18707, 300.63504) (548.6047, 415.24503) 501 300 548 415 524.5 357.5
2 (966.0561, 213.89882) (1010.95636, 321.63043) 966 213 1010 321 988.0 267.0
3 (775.5949, 99.51255) (807.30255, 185.5091) 775 99 807 185 791.0 142.0
4 (173.25558, 290.7064) (221.5165, 404.7594) 173 290 221 404 197.0 347.0
... ... ... ... ... ... ... ... ...
34 (763.8143, 0.58402455) (785.24835, 47.05696) 763 0 785 47 774.0 23.5
35 (415.5593, 0.0) (442.8612, 36.811195) 415 0 442 36 428.5 18.0
36 (924.0795, 617.972) (994.36, 702.72516) 924 617 994 702 959.0 659.5
37 (752.81573, 2.0422451) (778.64526, 46.801693) 752 2 778 46 765.0 24.0
38 (240.47375, 305.00726) (291.56476, 416.08606) 240 305 291 416 265.5 360.5

5367 rows × 8 columns

In [30]:
x =df_concat['xmean']
y =df_concat['ymean']

plt.hist2d(x,y, bins=[np.arange(0,1280,20),np.arange(0,720,20)])
plt.gca().invert_yaxis()
In [31]:
l=range(0,136)
In [32]:
accuracy = pd.DataFrame(list(zip(l, q, q2)),columns =['Tiempo', 'Modelo_1_80%', 'Modelo_2_50%'])
accuracy2=accuracy.stack().reset_index()
accuracy3=accuracy2[accuracy2['level_1']!='Tiempo']
accuracy3=accuracy3.rename(columns={accuracy3.columns[2]: "Cantidad"})
accuracy3=accuracy3.rename(columns={accuracy3.columns[0]: "Segundos"})
accuracy3=accuracy3.rename(columns={accuracy3.columns[1]: "Y"})
accuracy3
Out[32]:
Segundos Y Cantidad
1 0 Modelo_1_80% 37
2 0 Modelo_2_50% 44
4 1 Modelo_1_80% 38
5 1 Modelo_2_50% 46
7 2 Modelo_1_80% 38
... ... ... ...
401 133 Modelo_2_50% 34
403 134 Modelo_1_80% 30
404 134 Modelo_2_50% 37
406 135 Modelo_1_80% 30
407 135 Modelo_2_50% 39

272 rows × 3 columns

In [33]:
import plotly.express as px
fig = px.line(accuracy3, x='Segundos', y='Cantidad', color='Y', markers=True,  title='Detección de Personas por Modelo')
fig.show()

8. Discusión¶

  • De las 136 imágenes procesadas el tiempo medio fue de 3.3 segundos. La gran mayoría de las imágenes se demora entre 3 a 4 segundos en ser procesadas, sin embargo, hay una imagen que se demoró más de 4.2 segundos.
  • La cantidad de personas detectadas en cada imagen va desde los 26 hasta los 42, con un promedio de 33 personas por cuadro.
  • Se realizó un experimento con supervión humana seleccionando imágenes de manera aleatoria para contar la cantidad de personas reconocidas por la red pre entrenada y la cantidad de personas totales. Al utilizar un umbral de detección del 80% a veces ocurre que no se detectan todas las personas, sobre todo cuando las estas están muy próximas. Por ejemplo, en un cuadro se llega a un accuracy del 93% detectadndo 41 personas reconocidas de 44 total de personas.
  • Sin embargo este punto es rápidamente mejorado al llevar el umbral a 50% de detección y, con esto, se alcanza un accuracy del 100%, es decir, se detecta exactamente la misma cantidad de personas que hay en la imagen validado con supervión humana. Se realiza un grafico comparativo s con la cantidad de personas detectada por cada algoritmo para cada cuadro en función del tiempo. Se observa que el modelo de detección con umbral del 50% detecta para cada cuadro más imagenes que el modelo con umbral de detección de 80%.

  • Finalmente se realiza un analisis de áreas de interes, el cual tiene el mayor valor para una aplicación de negocio real. Este mismo prototipo podría ser utilizado para medir flujo de personas en cualquier retail, más aun, detectar zonas de interés relevantes que concentren mayor cantidad o flujo de personas.

In [ ]: